﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using MouseExtender.Logic;
using MouseExtender.Logic.Common;
using MouseExtender.Logic.Entities;
using MouseExtender.Logic.Enums;
using MouseExtender.Logic.Events;
using MouseExtender.Logic.Helpers;
using MouseExtender.Logic.Managers;
using FormsDialogResult = System.Windows.Forms.DialogResult;
using FormsOpenFileDialog = System.Windows.Forms.OpenFileDialog;

namespace MouseExtender.Controls.UserControls
{
    /// <summary>
    /// Interaction logic for RunningProgramsUC.xaml
    /// </summary>
    public partial class RunningProgramsUC : UserControl
    {
        Dictionary<LauncherItem, LauncherItemUC> _launcherItems = null;

        public RunningProgramsUC()
        {
            InitializeComponent();
        }

        internal void Refresh()
        {
            this.Visibility = Visibility.Visible;
            wpRunningPrograms.Children.Clear();
            _launcherItems = new Dictionary<LauncherItem, LauncherItemUC>();
            wpRunningPrograms.Width = App.MainWindowInstance.ucLauncher.ActivePanel.ActualWidth;
            ThreadPool.QueueUserWorkItem(LoadRunningPrograms);
        }

        private void LoadRunningPrograms(object state)
        {
            Process[] processes = ProcessHelper.GetCurrentUserProcesses();
            List<LauncherItem> items = new List<LauncherItem>();
            for (int i = 0; i < processes.Length; i++)
            {
                using (Process userProcess = processes[i])
                {
                    LauncherItem newItem = new LauncherItem();
                    newItem.ItemNumber = i;
                    string fileName = userProcess.MainModule.FileName;
                    newItem.LaunchPath = fileName.ToLower();
                    string arguments = userProcess.StartInfo.Arguments;
                    if (!String.IsNullOrEmpty(arguments))
                    {
                        arguments = arguments.ToLower();
                    }
                    newItem.Arguments = arguments;
                    string directory = userProcess.StartInfo.WorkingDirectory;
                    if (String.IsNullOrEmpty(directory))
                    {
                        directory = Path.GetDirectoryName(fileName);
                    }
                    string toolTip = userProcess.MainModule.FileVersionInfo.FileDescription;
                    if (String.IsNullOrEmpty(toolTip))
                    {
                        toolTip = Path.GetFileName(userProcess.MainModule.FileName);
                    }
                    newItem.ToolTip = toolTip;
                    newItem.WorkingDirectory = directory.ToLower();
                    items.Add(newItem);
                }
            }
            //timeout to allow popup expand and then load icons (it takes CPU)
            //without timeout opening popup & loading items is ugly
            Thread.Sleep(150);
            Dispatcher.Invoke(new Action<List<LauncherItem>>(InitializeItems), DispatcherPriority.Normal, items);
        }

        private void InitializeItems(List<LauncherItem> items)
        {
            MainWindow mainWindow = App.MainWindowInstance;
            foreach (LauncherItem item in items)
            {
                LauncherItemUC newItem = CreateLauncherItemUC(item);
                _launcherItems.Add(item, newItem);
                wpRunningPrograms.Children.Add(newItem);
            }
            ThreadPool.QueueUserWorkItem(LoadLauncherIcons, items);
        }

        private void LoadLauncherIcons(object state)
        {
            List<LauncherItem> items = (List<LauncherItem>)state;
            foreach (var item in items)
            {
                try
                {
                    BitmapSource source = IconHelper.GetItemIcon(item);
                    source.Freeze();
                    Dispatcher.Invoke(new Action<LauncherItem, BitmapSource>(ApplyIconToItem), item, source);
                }
                catch (Exception ex)
                {
                    Logger.HandleNonCriticalError(ex);
                    Dispatcher.Invoke(new Action<LauncherItem>(SetItemAsBroken), item);
                }
            }
        }

        private void SetItemAsBroken(LauncherItem item)
        {
            LauncherItemUC itemUC = _launcherItems[item];
            itemUC.SetBrokenFileStyle();
            itemUC.toolTip.Content = ResourceManager.GetMessage(Constants.ResourceKeys.Launcher_FileNotExissMessageKey);
            itemUC.IsBroken = true;
        }

        private void ApplyIconToItem(LauncherItem item, BitmapSource source)
        {
            LauncherItemUC itemUC = _launcherItems[item];
            itemUC.IsBroken = false;
            itemUC.imgIcon.Source = source;
            if (item.ItemColor == Constants.Defaults.ItemColor || item.ItemColor == Constants.Defaults.BrokenItemColor)
            {
                if (!itemUC.IsUrl)
                {
                    itemUC.ItemColor = IconHelper.GetIconMatchedColor(source, 9);
                }
                else
                {
                    Random random = new Random(DateTime.Now.Millisecond);
                    Color randomColor = TabColors.Colors[random.Next(0, 9)];
                    HSBColor color = HSBColor.FromColor(System.Drawing.Color.FromArgb(randomColor.R, randomColor.G, randomColor.B));
                    HSBColor newColor = new HSBColor(color.H, random.Next(100, 150), random.Next(70, 85));
                    itemUC.ItemColor = Color.FromRgb(newColor.Color.R, newColor.Color.G, newColor.Color.B);
                }
            }
        }

        private LauncherItemUC CreateLauncherItemUC(LauncherItem item)
        {
            LauncherItemUC newItemUC = null;
            newItemUC = new LauncherItemUC(item);
            newItemUC.DisableExtendedBehavior = true;
            newItemUC.ToolTipContent = item.ToolTip;
            try
            {
                newItemUC.IsBroken = false;
                BitmapSource source = IconHelper.GetItemIcon(item);
                newItemUC.imgIcon.Source = source;
                if (item.ItemColor == Constants.Defaults.ItemColor || item.ItemColor == Constants.Defaults.BrokenItemColor)
                {
                    if (!newItemUC.IsUrl)
                    {
                        newItemUC.ItemColor = IconHelper.GetIconMatchedColor(source, 9);
                    }
                    else
                    {
                        Random random = new Random(DateTime.Now.Millisecond);
                        Color randomColor = TabColors.Colors[random.Next(0, 9)];
                        HSBColor color = HSBColor.FromColor(System.Drawing.Color.FromArgb(randomColor.R, randomColor.G, randomColor.B));
                        HSBColor newColor = new HSBColor(color.H, random.Next(100, 150), random.Next(70, 85));
                        newItemUC.ItemColor = Color.FromRgb(newColor.Color.R, newColor.Color.G, newColor.Color.B);
                    }
                }
                newItemUC.ItemSelecting += new LaunchItemSelecting(newItemUC_ItemSelecting);
            }
            catch (Exception ex)
            {
                Logger.HandleNonCriticalError(ex);
                newItemUC.SetBrokenFileStyle();
                newItemUC.toolTip.Content = ResourceManager.GetMessage(Constants.ResourceKeys.Launcher_FileNotExissMessageKey);
                newItemUC.IsBroken = true;
            }

            switch (SettingsManager.CurrentSettings.IconSize)
            {
                case IconSize.Icon16x16:
                    newItemUC.iconPlaceholder.Height = newItemUC.iconPlaceholder.Width =
                    newItemUC.itemButton.Height = newItemUC.itemButton.Width = 22;
                    newItemUC.iconPlaceholder.Clip = new RectangleGeometry(new Rect(-1, -1, 24, 24), 5, 5);
                    newItemUC.imgIcon.Width = newItemUC.imgIcon.Height = 16;
                    newItemUC.imgIcon.Margin = new Thickness(3);
                    newItemUC.glare.Width = 22;
                    newItemUC.glare.Height = 11;
                    Margin = new Thickness(0);
                    break;
                case IconSize.Icon32x32:
                default:
                    newItemUC.imgIcon.Width = newItemUC.imgIcon.Height = 32;
                    break;
            }

            return newItemUC;
        }

        /// <summary>
        /// checks if strings are equal or are both empty/null
        /// </summary>
        private bool AreStringsEqualOrEmpty(string string1, string string2)
        {
            return (string1 == string2) || ((String.IsNullOrEmpty(string1)) && (String.IsNullOrEmpty(string2)));
        }

        private void RemoveLauncherItemUCFromRunningPrograms(LauncherItem item)
        {
            var pair = _launcherItems.FirstOrDefault(
                    p =>
                        (p.Key.LaunchPath.ToLower() == item.LaunchPath)
                        &&
                        (AreStringsEqualOrEmpty(p.Key.WorkingDirectory.ToLower(), item.WorkingDirectory))
                        &&
                        (AreStringsEqualOrEmpty(p.Key.Arguments.ToLower(), item.Arguments))
                        );
            if (pair.Value != null)
            {
                wpRunningPrograms.Children.Remove(pair.Value);
                _launcherItems.Remove(item);
            }
        }

        private void newItemUC_ItemSelecting(object sender, LaunchItemSelectingEventArgs e)
        {
            e.LaunchingCancelled = true;
            bool isMultiple = false;
            LauncherItem item = new LauncherItem()
            {
                LaunchPath = e.LauncherItem.LaunchPath,
                WorkingDirectory = e.LauncherItem.WorkingDirectory,
                Arguments = e.LauncherItem.Arguments,
                ToolTip = e.LauncherItem.ToolTip,
            };
            if (KeyboardHelper.IsControl())
            {
                //hide clicked item
                Dispatcher.Invoke(new Action<LauncherItem>(RemoveLauncherItemUCFromRunningPrograms), e.LauncherItem);
                //allow multiple selection
                isMultiple = true;
            }
            if (KeyboardHelper.IsShift())
            {
                //run new instance?
                e.LaunchingCancelled = false;
                return;
            }
            //this.Visibility = Visibility.Collapsed;
            if (RunningProgramSelected != null)
                RunningProgramSelected(this, new LaunchItemSelectedEventArgs(item, isMultiple));
        }

        private void btnAddProgram_Click(object sender, RoutedEventArgs e)
        {
            FormsOpenFileDialog ofdExcludedProgram = (FormsOpenFileDialog)App.Current.Resources["ofdAddExcludedProgram"];
            ofdExcludedProgram.DereferenceLinks = true;
            FormsDialogResult dialogResult = ofdExcludedProgram.ShowDialog();
            if (dialogResult == FormsDialogResult.OK)
            {
                LauncherItem item = new LauncherItem()
                {
                    LaunchPath = ofdExcludedProgram.FileName,
                    WorkingDirectory = System.IO.Path.GetDirectoryName(ofdExcludedProgram.FileName),
                };

                this.Visibility = Visibility.Collapsed;
                if (RunningProgramSelected != null)
                    RunningProgramSelected(this, new LaunchItemSelectedEventArgs(item));
            }
        }

        private void btnClose_Click(object sender, RoutedEventArgs e)
        {
            this.Visibility = Visibility.Collapsed;
            if (Closed != null)
                Closed(this, EventArgs.Empty);
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            btnClose.Focus();
        }

        public event LaunchItemSelected RunningProgramSelected;
        public event EventHandler Closed;
    }
}
